﻿using UnityEngine;

//从独立游戏学习开发08- 00:00
public class PlayerMovement : MonoBehaviour
{
    private Rigidbody2D rb;
    private BoxCollider2D coll;

    [Header("移动参数")]
    public float speed = 8f;
    public float crouchSpeedDivisor = 3f;

    [Header("跳跃参数")]
    public float jumpForce = 6.3f;
    public float jumpHoldForce = 1.9f;
    public float jumpHoldDuration = 0.1f;
    public float crouchJumpBoost = 2.5f;
    public float hangingJumpForce = 15.0f;

    float jumpTime;

    [Header("状态")]
    public bool isCrouch;
    public bool isOnGround;
    public bool isJump;
    public bool isHeadBlocked;
    public bool isHanging;

    [Header("环境检测")]
    public float footOffset = 0.4f;
    public float headClearance = 0.5f;

    public float groundDistance = 0.2f;
   
    public float eyeHeight = 1.5f;
    public float grabDistance = 0.4f;
    public float reachOffset = 0.7f;


    float playerHeight;
  
   
  
    public float blockCheckRatio = 0.8f; // 需要乘一个小于约0.8的系数才能正确地悬挂
    



    public LayerMask groundLayer;

    public float xVelocity;

    //按键设置
    public bool jumpPressed;
    public bool jumpHeld;
    public bool crouchHeld;
    public bool crouchPressed;


    //碰撞体尺寸
    Vector2 colliderStandSize;
    Vector2 colliderStandOffset;
    Vector2 colliderCrouchSize;
    Vector2 colliderCrouchOffset;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        coll = GetComponent<BoxCollider2D>();

        playerHeight = coll.size.y;
        colliderStandSize = coll.size;
        colliderStandOffset = coll.offset;
        colliderCrouchSize = new Vector2(coll.size.x, coll.size.y / 2f);
        colliderCrouchOffset = new Vector2(coll.offset.x, coll.offset.y / 2f);

    }

    void Update()
    {

        if(!GameManager.GameOver())
        {
            jumpPressed = Input.GetButtonDown("Jump");
            jumpHeld = Input.GetButton("Jump");
            crouchHeld = Input.GetButton("Crouch");
            crouchPressed = Input.GetButtonDown("Crouch");
        }
        else    
            return;
        
        

        if(GameManager.GameOver())
        {
            return;
        }
        if (Input.GetButtonDown("Jump"))
            jumpPressed = true;
        jumpHeld = Input.GetButton("Jump");
        crouchHeld = Input.GetButton("Crouch");
        crouchPressed = Input.GetButtonDown("Crouch");

    }

    void PhysicsCheck()
    {
        //Vector2 pos = transform.position;
        //Vector2 offset = new Vector2(-footOffset, 0f);
        //
        //RaycastHit2D leftCheck = Physics2D.Raycast(pos + offset, Vector2.down, 
        //    groundDistance, groundLayer);
        //Debug.DrawRay(pos + offset, Vector2.down, Color.red, 0.2f);

        // 左右脚射线
        RaycastHit2D leftCheck = Raycast(new Vector2(-footOffset, 0f), 
            Vector2.down, groundDistance, groundLayer);
        RaycastHit2D rightCheck = Raycast(new Vector2(footOffset, 0f), 
            Vector2.down, groundDistance, groundLayer);

        if (leftCheck || rightCheck)
        {
            isOnGround = true;
        }
        else
        {
            isOnGround = false;
        }

        // 头顶射线
        RaycastHit2D headCheck = Raycast(new Vector2(0f, coll.size.y),
            Vector2.up, headClearance, groundLayer);

        if (headCheck)
        {
            isHeadBlocked = true;
        }
        else
        {
            isHeadBlocked = false;
        }

        float direction = transform.localScale.x;
        Vector2 grabDir = new Vector2(direction, 0f);
        RaycastHit2D blockedCheck = Raycast(

            new Vector2(footOffset * direction, playerHeight), grabDir,
            grabDistance, groundLayer);
      
          

          
        RaycastHit2D wallCheck = Raycast(
            new Vector2(footOffset * direction * blockCheckRatio, eyeHeight), grabDir,

            grabDistance, groundLayer);
        RaycastHit2D ledgeCheck = Raycast(
            new Vector2(reachOffset * direction, playerHeight), Vector2.down,
            grabDistance, groundLayer);

        if(!isOnGround && rb.velocity.y < 0f && ledgeCheck && wallCheck 
            && !blockedCheck)
        {
            Vector3 pos = transform.position;

            pos.x += (wallCheck.distance - 0.05f) * direction;

            pos.x += (wallCheck.distance - footOffset * (1 - blockCheckRatio) - 0.05f) * direction; //射线被blockCheckRatio调整过，需要补回来。

            pos.y -= ledgeCheck.distance;

            transform.position = pos;

            rb.bodyType = RigidbodyType2D.Static;
            isHanging = true;
        }
    }

    private void FixedUpdate()
    {
        if (GameManager.GameOver())
        {
            return;
        }
        PhysicsCheck();

        GroundMovement();
        MidAirMovement();

        MidAirMovement();
        GroundMovement();

    }

    void GroundMovement()
    {
        if (isHanging)
        {
            return;
        }
        if (crouchHeld && !isCrouch && isOnGround)
        {
            Crouch();
        }
        else if(!crouchHeld && isCrouch && !isHeadBlocked)
        {
            StandUp();
        }
        else if(!isOnGround && isCrouch)
        {
            StandUp();
        }


        xVelocity = Input.GetAxis("Horizontal");

        if (isCrouch)
        {
            xVelocity /= crouchSpeedDivisor;
        }

        rb.velocity = new Vector2(xVelocity * speed, rb.velocity.y);

        FlipDirection();
    }

    void MidAirMovement()
    {
        if (isHanging)
        {
            if (jumpPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                rb.velocity = new Vector2(rb.velocity.x, hangingJumpForce);
                isHanging = false;
            }

            if (crouchPressed)
            {
                rb.bodyType = RigidbodyType2D.Dynamic;
                isHanging = false;
            }
        }
        if(jumpPressed && isOnGround && !isJump && !isHeadBlocked)
        {
            if(isCrouch)
            {
                StandUp();
                rb.AddForce(new Vector2(0f, crouchJumpBoost), ForceMode2D.Impulse);               
            }

            isOnGround = false;
            isJump = true;

            jumpTime = Time.time + jumpHoldDuration;

            rb.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);

            AudioManager.PlayJumpAudio();
        }
        else if (isJump)
        {
            if(jumpHeld)
            {
                rb.AddForce(new Vector2(0f, jumpHoldForce), ForceMode2D.Impulse);
            }
            if (jumpTime < Time.time)
            {
                isJump = false;
            }
        }

        if(jumpPressed)
            jumpPressed = false;

    }

    void FlipDirection()
    {
        if (xVelocity < 0)
        {
            transform.localScale = new Vector3(-1, 1, 0);
        }
        if (xVelocity > 0)
        {
            transform.localScale = new Vector3(1, 1, 0);
        }
    }

    void Crouch()
    {
        isCrouch = true;
        coll.size = colliderCrouchSize;
        coll.offset = colliderCrouchOffset;
    }

    void StandUp()
    {
        isCrouch = false;
        coll.size = colliderStandSize;
        coll.offset = colliderStandOffset;
    }

    RaycastHit2D Raycast(Vector2 offset, Vector2 rayDirection, float length, 
        LayerMask layer)
    {
        Vector2 pos = transform.position;

        RaycastHit2D hit = Physics2D.Raycast(pos + offset, rayDirection, 
            length, layer);

        Color color = hit ? Color.red : Color.green;
        Debug.DrawRay(pos + offset, rayDirection * length, color);

        return hit;
    }


}
